//----------------------------------Include-------------------------------------
#include <stdint.h>
#include "mcu.h"
//------------------------------------------------------------------------------

//电源管理（多个片上电源）
//  DCDC 电压转换器，提供 0.9∼1.3V 输出，为系统电源域的电路供电，可调节 DCDC 输出，以支持动态电压频率调整 DVFS，来优化运行时的功耗
//  LDOPMC，典型值 1.1V 输出的线性稳压器，为电源管理域的电路供电
//  LDOOTP，典型值 2.5V 输出的线性稳压器，为 OTP 供电，仅可在烧写 OTP 时打开
//（系统电源域专指由 VDD_SOC 供电的逻辑和存储电路）
//（电源管理域专指由 VPMC 供电的逻辑和存储电路）
//（电池备份域专指由 VBAT 供电的逻辑和存储电路）

//XTAL32K 和 RC32K 共同构成 CLK_32K 时钟源。当 XTAL32K 频率稳定时，CLK_32K 来自 XTAL32K 的输出时钟，
//当 XTAL32K 尚未稳定或没有外接 32K 晶振时，CLK_32K 来自 RC32K 的输出时钟。两个时钟之间的切换自动进行。
//XTAL32K 默认自动使能，即电池备份域电源有效时就开始驱动外部 32K 晶振进行工作。
//CLK_32K 直接为电池备份域的模块提供时钟

//XTAL24M 和 RC24M 共同构成 CLK_24M 时钟源。当 XTAL24M 使能并频率稳定时，CLK_24M 来自 XTAL24M的输出时钟，
//当 XTAL24M 关闭或尚未稳定时，CLK_24M 来自 RC24M 的输出时钟。两个时钟之间的切换自动进行。
//XTAL24M 默认自动使能，其在低功耗模式下的开关控制请参考系统控制模块。
//CLK_24M 直接为电源管理域的模块提供时钟。

//内置 3 个 PLL 用以生成系统所需要的各种频率的时钟，其中 PLL0 有 3 路，PLL1 和 PLL2 各有 2 路独立分频的时钟输出，所以 PLL 时钟源共有 7 个
//PLL 默认使用 XTAL24M 时钟作为参考时钟，各 PLL 已预先设置了默认工作频率
//选择值  时钟源     默认频率   说明
//0      CLK_24M     24MHz    24MHz 时钟源
//1      PLL0CLK0   400MHz    默认作为处理器的时钟源
//2      PLL0CLK1   333MHz
//3      PLL0CLK2   250MHz
//4      PLL1CLK0   480MHz
//5      PLL1CLK1   320MHz
//6      PLL2CLK0   516.096MHz
//7      PLL2CLK1   451.584MHz
//每个功能时钟从上面8选1，并且可单独设置分频系数进行分频，分频系数范围为从 1 到 256 的任意整数
//为便于使用，各功能时钟已预先设置了时钟源选择和分频系数
//功能时钟名称       默认时钟源    默认分频系数    默认频率   应用
//CLK_TOP_HART0     PLL0CLK0         1          400MHz    CPU0 核心/ILM0/DLM0/FGPIO0
//CLK_TOP_MCHTMR0   CLK24M           1           24MHz    MCHTMR0 计时
//CLK_TOP_MCHTMR1   CLK24M           1           24MHz    MCHTMR1 计时
//CLK_TOP_AHB0      CLK_TOP_HART0    2          200MHz    外设总线，由 CPU 时钟分频生成，和 CPU 同步
//CLK_TOP_AXI0      CLK_TOP_HART0    2          200MHz    系统总线，由 CPU 时钟分频生成，和 CPU 同步
//CLK_TOP_XPI0      PLL0CLK1         2          166MHz*   XPI0 接口（实际频率与启动配置有关）
//CLK_TOP_GPTMR0~3  PLL0CLK0         4          100MHz    GPTMR0~3 计时
//CLK_TOP_UART0~7   PLL1CLK0         6           80MHz    UART0~7 接口
//CLK_TOP_I2C0~3    PLL1CLK0         6           80MHz    I2C0~3 接口
//CLK_TOP_SPI0~3    PLL1CLK0         6           80MHz    SPI0~3 接口
//CLK_TOP_CAN0~3    PLL1CLK0         6           80MHz    CAN0~3 接口
//CLK_TOP_PTPC      PLL0CLK0         4          100MHz    PTPC 计时
//CLK_TOP_PTP0      PLL0CLK0         4          100MHz    PTP0
//CLK_TOP_ANA0~4    PLL0CLK0         2          200MHz    ADC0/ADC1/ADC2/DAC0/DAC1 备选时钟
//CLK_TOP_REF0~1    PLL0CLK2         5           50MHz    REF0~1 参考时钟
//CLK_TOP_LIN0~3    PLL1CLK0         6           80MHz    LIN0~3 接口
//CLK_TOP_ADC0~2    CLK_TOP_ANA0~2              200MHz    ADC0~2
//CLK_TOP_DAC0~1    CLK_TOP_ANA3~4              200MHz    DAC0~1

//还有一部分模块没有使用功能时钟而是直接连接时钟源，包括电池备份域和电源管理域的全部模块，还包括系统电源域的部分计时模块
//电池备份域模块
//模块     时钟源
//RTC     CLK_32K
//BGPIO   CLK_32K
//TAMP    CLK_32K
//电源管理域模块
//模块     时钟源
//PTMR    CLK_24M
//PWDG    CLK_24M 和 CLK_32K
//PUART   CLK_24M
//PGPIO   CLK_24M
//系统电源域模块
//模块           时钟源
//WDG0~WDG1     CLK_32K 和 CLK_TOP_AHB
//USB0          CLK_24M

//------------------------------------Type--------------------------------------
typedef struct{
  uint32_t  cpuclk;
}t_clk;
//------------------------------------------------------------------------------

//-----------------------------------Macro--------------------------------------
//内部时钟
#define RC32K                   (32000)
#define RC24M                (24000000)
//外部时钟
#define XTAL32K                 (32768)     //XTAL32K 默认自动使能
#define XTAL24M              (24000000)     //XTAL24M 默认自动使能
//------------------------------------------------------------------------------

//--------------------------------Static Var------------------------------------
//static t_clk                 nt_clk;
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
void mcu_sys_clock(void)
{
  uint32_t cpu0_freq = clock_get_frequency(clock_cpu0);

  if (cpu0_freq == PLLCTL_SOC_PLL_REFCLK_FREQ) {
    pllctlv2_xtal_set_rampup_time(HPM_PLLCTLV2, 32UL * 1000UL * 9U);    /* Configure the External OSC ramp-up time: ~9ms */
    sysctl_clock_set_preset(HPM_SYSCTL, 2);                             /* Select clock setting preset1 */
  }

  /* Add most Clocks to group 0 */
  /* not open uart clock in this API, uart should configure pin function before opening clock */
  clock_add_to_group(clock_cpu0,    0);
  clock_add_to_group(clock_ahbp,    0);
  clock_add_to_group(clock_axic,    0);
  clock_add_to_group(clock_axis,    0);

  clock_add_to_group(clock_mchtmr0, 0);
  clock_add_to_group(clock_xpi0,    0);
  clock_add_to_group(clock_gptmr0,  0);
  clock_add_to_group(clock_gptmr1,  0);
  clock_add_to_group(clock_gptmr2,  0);
  clock_add_to_group(clock_gptmr3,  0);
  clock_add_to_group(clock_i2c0,    0);
  clock_add_to_group(clock_i2c1,    0);
  clock_add_to_group(clock_i2c2,    0);
  clock_add_to_group(clock_i2c3,    0);
  clock_add_to_group(clock_lin0,    0);
  clock_add_to_group(clock_lin1,    0);
  clock_add_to_group(clock_lin2,    0);
  clock_add_to_group(clock_lin3,    0);
  clock_add_to_group(clock_spi0,    0);
  clock_add_to_group(clock_spi1,    0);
  clock_add_to_group(clock_spi2,    0);
  clock_add_to_group(clock_spi3,    0);
  clock_add_to_group(clock_can0,    0);
  clock_add_to_group(clock_can1,    0);
  clock_add_to_group(clock_can2,    0);
  clock_add_to_group(clock_can3,    0);
  clock_add_to_group(clock_ptpc,    0);
  clock_add_to_group(clock_ref0,    0);
  clock_add_to_group(clock_ref1,    0);

  clock_add_to_group(clock_watchdog0, 0);
  clock_add_to_group(clock_sdp,       0);
  clock_add_to_group(clock_xdma,      0);
  clock_add_to_group(clock_ram0,      0);
  clock_add_to_group(clock_usb0,      0);
  clock_add_to_group(clock_kman,      0);
  clock_add_to_group(clock_gpio,      0);
  clock_add_to_group(clock_mbx0,      0);
  clock_add_to_group(clock_hdma,      0);
  clock_add_to_group(clock_rng,       0);
  clock_add_to_group(clock_mot0,      0);
  clock_add_to_group(clock_mot1,      0);
  clock_add_to_group(clock_mot2,      0);
  clock_add_to_group(clock_mot3,      0);
  clock_add_to_group(clock_acmp,      0);
  clock_add_to_group(clock_synt,      0);
  clock_add_to_group(clock_lmm0,      0);
  clock_add_to_group(clock_lmm1,      0);

  clock_add_to_group(clock_adc0, 0);
  clock_add_to_group(clock_adc1, 0);
  clock_add_to_group(clock_adc2, 0);

  clock_add_to_group(clock_dac0, 0);
  clock_add_to_group(clock_dac1, 0);

  clock_add_to_group(clock_tsns, 0);
  clock_add_to_group(clock_crc0, 0);
  clock_add_to_group(clock_sdm0, 0);

  /* Connect Group0 to CPU0 */
  clock_connect_group_to_cpu(0, 0);

  /* Add the CPU1 clock to Group1 */
  clock_add_to_group(clock_mchtmr1, 1);

  /* Connect Group1 to CPU1 */
  clock_connect_group_to_cpu(1, 1);

  /* Bump up DCDC voltage to 1275mv */
  pcfg_dcdc_set_voltage(HPM_PCFG, 1275);

  /* Connect CAN2/CAN3 to pll0clk0*/
  clock_set_source_divider(clock_can2, clk_src_pll0_clk0, 1);
  clock_set_source_divider(clock_can3, clk_src_pll0_clk0, 1);

  /* Configure CPU to 600MHz, AXI/AHB to 200MHz */
  sysctl_config_cpu0_domain_clock(HPM_SYSCTL, clock_source_pll1_clk0, 1, 3, 3);

  /* Configure PLL1_CLK0 Post Divider to 1 */
  pllctlv2_set_postdiv(HPM_PLLCTLV2, 1, 0, 0);
  pllctlv2_init_pll_with_freq(HPM_PLLCTLV2, 1, 600000000);
  clock_update_core_clock();

  /* Configure mchtmr to 24MHz */
  clock_set_source_divider(clock_mchtmr0, clk_src_osc24m, 1);
  clock_set_source_divider(clock_mchtmr1, clk_src_osc24m, 1);
}
//------------------------------------EOF---------------------------------------


